﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

namespace SharpShare.Afp.Configuration {
    public class AfpUamTypesConverter : TypeConverter {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }
        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
            if (destinationType == typeof(string)) {
                AfpUamConfigurationElementCollection collection = (AfpUamConfigurationElementCollection)value;
                var names = collection.Cast<AfpUamConfigurationElement>()
                    .Select(s => s.Type.GetCustomAttribute<DisplayNameAttribute>() ?? new DisplayNameAttribute(s.Type.Name))
                    .Select(s => s.DisplayName);
                return string.Join(", ", names);
            }

            return base.ConvertTo(context, culture, value, destinationType);
        }
        public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
            PropertyDescriptorCollection collection = new PropertyDescriptorCollection(
                GetUamTypes()
                    .Select(t => new UamPropertyDescriptor(t))
                    .ToArray()
            );

            return collection;
        }
        public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
            return true;
        }

        private static IEnumerable<Type> GetUamTypes() {
            var types = System.Reflection.Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => t.IsClass)
                .Where(t => typeof(Afp.Protocol.Security.IAfpUserAuthenticationMethod).IsAssignableFrom(t));

            return types;
        }

        private class UamPropertyDescriptor : PropertyDescriptor {
            public UamPropertyDescriptor(Type uamType)
                : base(uamType.Name, null) {
                this.UamType = uamType;
                this.AttributeArray = uamType
                    .GetCustomAttributes<Attribute>()
                    .Concat(new Attribute[] { 
                        new TypeConverterAttribute(typeof(SharpShare.Configuration.EnabledBooleanConverter)) 
                    })
                    .ToArray();

            }

            public Type UamType { get; private set; }

            public override bool CanResetValue(object component) {
                return false;
            }

            public override Type ComponentType {
                get { return typeof(AfpUamConfigurationElementCollection); }
            }

            public override object GetValue(object component) {
                AfpUamConfigurationElementCollection collection = (AfpUamConfigurationElementCollection)component;
                return (collection.Cast<AfpUamConfigurationElement>().Any(e => e.Type == this.UamType));
            }

            public override bool IsReadOnly {
                get { return false; }
            }

            public override Type PropertyType {
                get { return typeof(bool); }
            }

            public override void ResetValue(object component) {
                throw new NotImplementedException();
            }

            public override void SetValue(object component, object value) {
                AfpUamConfigurationElementCollection collection = (AfpUamConfigurationElementCollection)component;
                bool enabled = (bool)value;
                if (enabled) {
                    collection.Add(this.UamType);
                } else {
                    collection.Remove(this.UamType);
                }

                if (collection.Count == 0) {
                    collection.Add(typeof(Afp.Protocol.Security.AfpNoUserAuthenticationMethod));
                }
            }

            public override bool ShouldSerializeValue(object component) {
                return true;
            }
        }
    }
}
